package com.cn.transfer.myanno;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;

@Component
public class MyServiceSacnnerRegistry implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        // 1、创建扫描器
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanDefinitionRegistry);

        // 添加扫描的注解
        scanner.addIncludeFilter(new AnnotationTypeFilter(MyService1.class));

        // 设置扫描路径
        scanner.scan("com.cn.transfer");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        //搜索被Interface注解的类。key为bean的id，value为bean的实例。
        //beanFactory.getBeansWithAnnotation返回时通过getBean方法将bean的实例化，如果bean中autowired注解的属性没有实例化就会注入null

        DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
        // 根据标签获取类名
        String[] ary = beanFactory.getBeanNamesForAnnotation(MyService1.class);
        if (ary != null && ary.length > 0) {
            for (String beanName : ary) {
                //通过Spring的beanName获取bean的类型
                Class<?> cls = beanFactory.getType(beanName);
                if (cls.getAnnotations() != null && cls.getAnnotations().length > 0) {
                    for (Annotation annotation : cls.getAnnotations()) {
                        if (annotation instanceof MyService1) {
                            MyService1 intfc = (MyService1) annotation;
                            //将全限定名注册为别名
                            this.registerAlias(beanFactory, beanName, cls.getName());

                            //其他别名注册
                            this.registerAlias(beanFactory, beanName, intfc.value());

                            //如果不做registerBeanDefinition，那么bean内的注解会无效(如Autowired)
                            /*RootBeanDefinition rbd = new RootBeanDefinition(cls);
                            dlbf.registerBeanDefinition(beanName, rbd);*/
                        }
                    }
                }
            }
        }

    }

    /**
     * 为bean注册别名
     * 注意：如果别名与bean的ID冲突，放弃别名注册
     *
     * @param factory ConfigurableListableBeanFactory
     * @param value   Interface的value
     */
    private void registerAlias(ConfigurableListableBeanFactory factory, String beanId, String value) {
        //防止别名覆盖bean的ID
        if (factory.containsBeanDefinition(value)) {
            return;
        } else {
            factory.registerAlias(beanId, value);
        }
    }
}
